package smack;

import java.io.*;
import java.util.*;

import org.jivesoftware.smack.*;
import org.jivesoftware.smack.packet.*;
import org.jivesoftware.smack.filter.*;
import org.jivesoftware.smackx.*;
import org.jivesoftware.smackx.filetransfer.*;

//todo filters have to be added [Done and tested]

public class SmackChat{

private static final String BYE="-bye", CHAT="-chat", CHATBUZZED="-chat-buzz", ROSTER="-rost", EXIT="-exit", STATUS="-stat", ADDENT="-addentry", REMENT="-rementry", FULLROST="-rost-full", ALLCOMM="-commands", FSEND="-fsend";

private static final char BEEP=7;

static String usr;
static String pwd;
static Roster rost;
static XMPPConnection conn;
static String currentlyWith="";
static String buzzedBy="";


private static boolean printAll=false;
static boolean chatBuzz=false;


	public static void addPacketListeners(Roster r, XMPPConnection conn, BufferedReader in){
Collection c=r.getEntries();
Iterator it=c.iterator();
while(it.hasNext()){
RosterEntry re=(RosterEntry)(it.next());
PacketFilter filter=new AndFilter(new PacketTypeFilter(Message.class),new FromContainsFilter(re.getUser()));
conn.addPacketListener(new IncomingChatListener(),filter);
}
}

	public static void sendFile(BufferedReader in)throws IOException{
ServiceDiscoveryManager sm=new ServiceDiscoveryManager(conn);
FileTransferManager man=new FileTransferManager(conn);
System.out.print("To? ");
String s=in.readLine();
if(rost.contains(s)){
OutgoingFileTransfer trans=man.createOutgoingFileTransfer(s);
System.out.println("<filename>,<comments>");
try{trans.sendFile(new File(in.readLine()),in.readLine());}catch(XMPPException e){System.err.println("Connection error");}
while(!trans.isDone()){

if(trans.getStatus().equals(FileTransfer.Status.error)) {
                  System.out.println("Error while transfer!!! " + trans.getError());
            } else {
                  //System.out.println(trans.getStatus());
                  System.out.println((100*trans.getProgress())+"% completed");
            }
            try{Thread.sleep(1000);}catch(Exception e){e.printStackTrace();}


}
System.out.println("100% completed");
}else System.out.println("Invalid address");
}

	public static void allCommands(){
System.out.println(ROSTER+"\t"+CHAT+"\t"+STATUS+"\t"+ADDENT);
System.out.println(REMENT+"\t"+FULLROST+"\t"+CHATBUZZED);
}

	public static void removeEntry(BufferedReader in)throws IOException{
System.out.println("username?");
String usr=in.readLine();
if(rost.contains(usr)){
Iterator c=rost.getEntries().iterator();
while(c.hasNext()){
RosterEntry x=(RosterEntry)c.next();
if(x.getUser().equals(usr)){try{rost.removeEntry(x);}catch(XMPPException e){System.err.println("Error while removing");} System.out.println(usr+" has been removed");}
}
}
else System.out.println("Invalid username");
}

	public static void addEntry(BufferedReader in)throws IOException{
System.out.println("<username>,<name>");
try{
String usr=in.readLine();
//kick if already registered address is entered
if(rost.contains(usr)){System.out.println("Entry already exists"); return;}
String name=in.readLine();
rost.createEntry(usr,name,null);
System.out.println("Entry subscription requested");
//reload not required
}catch(XMPPException e){System.err.println("Connection error");}
}

	public static Presence setStatus(BufferedReader in) throws IOException{
System.out.println("Presence: type:available/unavailable, status, mode:available/chat/dnd/xa");
Presence pr;
try{
pr=new Presence(Presence.Type.valueOf(in.readLine()),in.readLine(),1,Presence.Mode.valueOf(in.readLine()));
}catch(NullPointerException ex){System.err.println("NullPointer"); pr=new Presence(Presence.Type.available,"",1,Presence.Mode.available);}
 catch(IllegalArgumentException ex){System.err.println("IllegalArgument"); pr=new Presence(Presence.Type.available,"",1,Presence.Mode.available);}
return pr;
}
	
	public static void printRoster(Roster r){
//r.reload();
System.out.println();
Collection c=r.getEntries();
Iterator it=c.iterator();
while(it.hasNext()){
RosterEntry re=(RosterEntry)(it.next());
//System.out.print(">>"+re.getName()+":"+re.getUser());
//System.out.println(" present?:"+r.getPresence(re.getUser()));
if((r.getPresence(re.getUser())).isAvailable() && !printAll)
	{
System.out.print(">>"+re.getName()+":"+re.getUser());
System.out.println(" : "+"is online "+r.getPresence(re.getUser()).getMode());
System.out.println(r.getPresence(re.getUser()).getStatus());
}

else if(printAll){
System.out.println(">>"+re.getName()+":"+re.getUser());
//System.out.println(" : "+"is online "+r.getPresence(re.getUser()).getMode());
//System.out.println(r.getPresence(re.getUser()).getStatus());
}

}
System.out.println();
}

	public static void chatWith(XMPPConnection conn, BufferedReader in) throws IOException{
ChatManager cm=conn.getChatManager();
String add="";
if(!chatBuzz){
System.out.print("With? ");
add=in.readLine();
}else if(chatBuzz){add=buzzedBy;}
if(!rost.contains(add)){System.out.println("Invalid address: "+add); return;}
currentlyWith=add; //very important
ChatListener cl=new ChatListener();
Chat chat=cm.createChat(add,cl);
System.out.println("Chat channel created successfully.. "+BYE+" to stop");
String c="";
while(!(c=in.readLine()).equals(BYE)){
try{
Message msg=new Message();
msg.setBody(c);
chat.sendMessage(msg);
}catch(XMPPException e){System.out.println("Failed to send msg..");}
}
System.out.println("Chat with "+add+" completed.");
chat.removeMessageListener(cl);
currentlyWith="";
}

	public static void main(String[] args) throws IOException{
String netarg="";
for(int ai=0;ai<args.length;ai++){netarg+=args[ai];}
System.out.println("Server?<server>,<port>,<resource>");
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
ConnectionConfiguration conConfig=new ConnectionConfiguration(in.readLine(),Integer.parseInt(in.readLine()),in.readLine());

System.out.println("<username>,<password>?");
usr=in.readLine();
pwd=in.readLine();

System.out.println("Creating connection for given configuration..");
conn=new XMPPConnection(conConfig);
/////////////////////////////////////////////////////////////
if(args.length==0){
conConfig.setSASLAuthenticationEnabled(false);
conConfig.setSecurityMode(ConnectionConfiguration.SecurityMode.enabled);
}
////////////////////////////////////////////////////////////
System.out.println("Done..");
try{
System.out.println("Attempting to connect..");
conn.connect();
System.out.println("Connected successfully");
}catch(XMPPException ex){
	System.out.println("Attempt failed..");
	System.exit(1);
}
try{

conn.login(usr,pwd);
System.out.println("Logged in as:"+conn.getUser());
Presence pr=new Presence(Presence.Type.available);
if(netarg.indexOf("-unav")!=-1){pr=new Presence(Presence.Type.unavailable);}
conn.sendPacket(pr);
}catch(XMPPException ex){
	System.out.println("Login failed..");
	System.exit(1);
}

System.out.println("Success!");
 rost=conn.getRoster();//

rost.addRosterListener(new RosterUpdater());
//printRoster(rost);
//System.out.print("?");
System.out.println("Configuring listeners...");
addPacketListeners(rost, conn, in);

System.out.println("Done.");
//////////////////////////////////COMMAND///////////////
String command="";
while(!command.equals(EXIT)){
System.out.println("Commands: "+ROSTER+" "+CHAT+" "+STATUS+" "+ALLCOMM+" "+EXIT);
System.out.print("?");
command=in.readLine();
if(command.equals(ROSTER)){rost.reload(); printRoster(rost);}
else if(command.equals(CHAT)){chatWith(conn,in);}
else if(command.equals(STATUS)){conn.sendPacket(setStatus(in));}
else if(command.equals(ADDENT)){addEntry(in);}
else if(command.equals(REMENT)){removeEntry(in);}
else if(command.equals(FULLROST)){printAll=true; rost.reload(); printRoster(rost); printAll=false;}
else if(command.equals(ALLCOMM)){allCommands();}
else if(command.equals(FSEND)){sendFile(in);}
else if(command.equals(CHATBUZZED)){if(chatBuzz==true) {chatWith(conn,in);}else{System.out.println("No one has buzzed you yet");} chatBuzz=false;}
}
///////////////////////////////////////////////////////


///////////////////////////////////////////////////////
System.out.println("Enter to disconnect..");
in.readLine();
conn.sendPacket(new Presence(Presence.Type.unavailable));
conn.disconnect();
System.out.println("Done..");
System.out.println("Created by spikey360 spikey360@yahoo.co.in");
System.out.println("Powered by Smack - http://www.igniterealtime.org/");
}

public static class ChatListener implements MessageListener{
public void processMessage(Chat chat, Message msg){
	if(msg.getType().equals(Message.Type.chat) && msg.getBody()!=null)	
	System.out.println(">>"+msg.getBody());
}
}

public static class IncomingListener implements MessageListener{
public void processMessage(Chat chat, Message msg){
	if(msg.getType().equals(Message.Type.chat) && msg.getBody()!=null && !currentlyWith.equals(chat.getParticipant())){
System.out.println("!Incoming message from "+chat.getParticipant());
System.out.println("\t["+msg.getBody()+"]");
}
}
}

public static class RosterUpdater implements RosterListener{
public void entriesAdded(Collection a){}
public void entriesDeleted(Collection a){}
public void entriesUpdated(Collection a){}
public void presenceChanged(Presence p){
//System.out.println(p);
//SmackTest.rost.reload();
//System.out.println("presenceChanged! not reloading..");

//SmackTest.printRoster(SmackTest.rost);

}
}

public static class IncomingChatListener implements PacketListener{

private String resourceCutter(String x){
if(x.indexOf("/")>-1){
//System.err.println("indexOf"+x.indexOf("/"));
String y=x.substring(0,x.indexOf("/"));
return y;}
return x;
}
public void processPacket(Packet packet){
if((resourceCutter(packet.getFrom())).equals(currentlyWith)){}
else{System.out.println("!!Incoming message from: "+resourceCutter(packet.getFrom())); System.out.print(BEEP);
//System.out.println(packet.getProperty("body"));
buzzedBy=resourceCutter(packet.getFrom());
chatBuzz=true;
}
}
}

public static class IncomingChatThread extends Thread{
public IncomingChatThread(XMPPConnection conn, BufferedReader in, String fromAddress){
this.conn=conn;
this.in=in;
add=fromAddress;
}

private String add;
private BufferedReader in;
private XMPPConnection conn;

public void run(){
try{
ChatManager cm=conn.getChatManager();
Chat chat=cm.createChat(add,new ChatListener());
System.out.println("Chat channel created successfully.. "+BYE+" to stop");
String c="";
while(!(c=in.readLine()).equals(BYE)){
try{
Message msg=new Message();
msg.setBody(c);
chat.sendMessage(msg);
}catch(XMPPException e){System.out.println("Failed to send msg..");}
}
System.out.println("Chat with "+add+" completed.");
}catch(IOException e){e.printStackTrace();}
}

}

}
